package cn.xiaopengstack.http;

import cn.xiaopengstack.api.IRAGService;
import cn.xiaopengstack.api.response.Response;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.redisson.api.RList;
import org.redisson.api.RedissonClient;
import org.springframework.ai.document.Document;
import org.springframework.ai.reader.tika.TikaDocumentReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore;
import org.springframework.core.io.PathResource;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;

/**
 * @author jiangyangang
 */
@RestController()
@CrossOrigin("*")
@Slf4j
@RequestMapping("/api/v1/rag/")
public class RAGController implements IRAGService {

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private TokenTextSplitter tokenTextSplitter;

    @Resource
    private PgVectorStore ollamaPgVectorStore;

    private final static String RAG_TAGS = "ragTags";

    /**
     * 查询RAG知识库标签
     * @return
     */
    @RequestMapping(value = "query_rag_tag_list", method = RequestMethod.GET)
    @Override
    public Response<List<String>> queryRagTags() {
        RList<String> ragTags = redissonClient.getList(RAG_TAGS);
        if (!ragTags.contains("无")) {
            ragTags.add("无");
        }

        return Response.success(ragTags.stream().toList());
    }

    /**
     * 上传知识文件
     * @param ragTag
     * @param files
     * @return
     */
    @RequestMapping(value = "file/upload", method = RequestMethod.POST, headers = "content-type=multipart/form-data")
    @Override
    public Response<String> uploadKnowledge(@RequestParam String ragTag,@RequestParam("files") List<MultipartFile> files) {
        log.info("上传知识库开始!");
        for (MultipartFile file : files) {
            TikaDocumentReader tikaDocumentReader = new TikaDocumentReader(file.getResource());
            List<Document> documents = tikaDocumentReader.get();
            List<Document> splitterDocuments = tokenTextSplitter.apply(documents);

            // 添加标签
            documents.forEach(doc -> doc.getMetadata().put("knowledge", ragTag));
            splitterDocuments.forEach(doc -> doc.getMetadata().put("knowledge", ragTag));

            ollamaPgVectorStore.accept(splitterDocuments);

            RList<String> ragTagsCache = redissonClient.getList(RAG_TAGS);
            if (!ragTagsCache.contains(ragTag)) {
                ragTagsCache.add(ragTag);
            }
        }
        log.info("上传知识库完成!");

        return Response.success(null);
    }

    @RequestMapping(value = "analyze_git_repository", method = RequestMethod.POST)
    @Override
    @SneakyThrows
    public Response<String> uploadGitKnowledge(@RequestParam(required = false) String tag,
                                               @RequestParam String repoUrl,
                                               @RequestParam String userName,
                                               @RequestParam String token) {
        String localPath = "./git-cloned-repo";
        String repoProjectName = extractProjectName(repoUrl);

        log.info("克隆路径：{}", new File(localPath).getAbsolutePath());
        // 删除目录
        FileUtils.deleteDirectory(new File(localPath));

        // 将项目clone到本地
        Git git = Git.cloneRepository()
                .setURI(repoUrl)
                .setDirectory(new File(localPath))
                .setCredentialsProvider(new UsernamePasswordCredentialsProvider(userName, token))
                .call();

        // 将clone下来的本地代码文件逐个解析上传
        Files.walkFileTree(Paths.get(localPath), new SimpleFileVisitor<>(){
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                log.info("{} 遍历本地代码文件，上传知识库：{}", repoProjectName, file.getFileName());
                try {
                    TikaDocumentReader reader = new TikaDocumentReader(new PathResource(file));
                    List<Document> documents = reader.get();
                    List<Document> documentSplitterList = tokenTextSplitter.apply(documents);

                    documents.forEach(doc -> doc.getMetadata().put("knowledge", repoProjectName));

                    documentSplitterList.forEach(doc -> doc.getMetadata().put("knowledge", repoProjectName));

                    ollamaPgVectorStore.accept(documentSplitterList);
                } catch (Exception e) {
                    log.error("遍历解析路径，上传知识库失败:{}", file.getFileName());
                }
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                log.info("访问文件失败: {} - {}", file.toString(), exc.getMessage());
                return FileVisitResult.CONTINUE;
            }
        });

        FileUtils.deleteDirectory(new File(localPath));

        // 添加知识库记录
        RList<String> elements = redissonClient.getList("ragTag");
        if (!elements.contains(repoProjectName)) {
            elements.add(repoProjectName);
        }

        git.close();
        log.info("遍历解析路径，上传完成:{}", repoUrl);

        return Response.success(null);
    }

private String extractProjectName(String repoUrl) {
    String[] parts = repoUrl.split("/");
    String projectNameWithGit = parts[parts.length - 1];
    return projectNameWithGit.replace(".git", "");
}
}
